package com.juejin.www.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.juejin.www.dao.UserDao;
import com.juejin.www.model.DO.User;
import com.juejin.www.model.DTO.PageDTO;
import com.juejin.www.model.DTO.UserDTO;
import com.juejin.www.model.VO.UserVO;
import com.juejin.www.service.UserService;
import com.juejin.www.utils.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Jacky
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public UserDTO login(UserDTO userDTO) {
        String key = "user:"+userDTO.getUsername();
        String cacheValue = stringRedisTemplate.opsForValue().get(key);
        UserDTO user;
        if(cacheValue!=null){
            user = JSON.parseObject(cacheValue,UserDTO.class);
        }else {
            user = userDao.getByUsername(userDTO.getUsername());
        }

        if(user != null){
            if(cacheValue==null){
                stringRedisTemplate.opsForValue().set(key, JSONObject.toJSONString(user));
            }
            //通过用户名查找盐值
            String salt = userDao.getSaltByUsername(userDTO.getUsername());

            //将用户输入的密码与盐值合并后进行MD5加密，获取加密后的密码
            String encrypt = MD5Util.encrypt(userDTO.getPassword() + salt);

            //重新封装加密后的密码
            userDTO.setPassword(encrypt);
        }

        UserDTO loginUser = userDao.getByUsernameAndPassword(userDTO);
        if(loginUser!=null){
            Integer role = userDao.getRole(loginUser.getId());
            loginUser.setRole(role);
        }
        return loginUser;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean register(UserDTO userDTO) {
        String key = "user:"+userDTO.getUsername();
        String cacheValue = stringRedisTemplate.opsForValue().get(key);
        UserDTO u;
        if(cacheValue!=null){
            u = JSON.parseObject(cacheValue,UserDTO.class);
        }else {
            u = userDao.getByUsername(userDTO.getUsername());
        }
        if(u == null){
            //生成盐值
            String salt = MD5Util.generateSalt(8);

            //将密码和盐值合并。一起进行MD5加密
            String encrypt = MD5Util.encrypt(userDTO.getPassword() + salt);

            //封装User对象
            User user  = new User(null,
                    userDTO.getUsername(),
                    encrypt,
                    salt,
                    userDTO.getName(),
                    userDTO.getGender(),
                    userDTO.getJob(),
                    userDTO.getAddress(),
                    0,0,1,
                    LocalDateTime.now(),
                    LocalDateTime.now());

            userDao.insertUser(user);
            userDao.insertRelUserRole(userDao.getByUsername(userDTO.getUsername()).getId(),2);
            return true;
        }else {
            return false;
        }
    }

    @Override
    public PageDTO<UserVO> getUsers(Integer currentPage,Integer pageSize) {
        Integer begin = (currentPage - 1) * pageSize;
        List<User> list = userDao.getList(begin,pageSize);
        List<UserVO> rows = list.stream()
                .map(user -> {
                    String gender;
                    if(user.getGender()==1){
                        gender = "男";
                    }else {
                        gender = "女";
                    }
                    return new UserVO(
                            user.getId(),
                            user.getUsername(),
                            user.getName(),
                            gender,
                            user.getJob(),
                            user.getAddress(),
                            user.getFollowCount(),
                            user.getBeFollowedCount(),
                            user.getStatus(),
                            null
                    );
                }).collect(Collectors.toList());
        Integer totalCount = userDao.getUsersTotalCount();
        PageDTO<UserVO> users = new PageDTO<>(totalCount,rows);
        return users;
    }

    @Override
    public UserVO getInfo(Integer id,Integer uid) {
        String username = userDao.getUsername(id);
        String key = "user:"+username;
        String cacheValue = stringRedisTemplate.opsForValue().get(key);
        UserDTO userDTO;
        if(cacheValue!=null){
            userDTO=JSON.parseObject(cacheValue,UserDTO.class);
        }else {
            userDTO = userDao.getById(id);
            stringRedisTemplate.opsForValue().set(key,JSONObject.toJSONString(userDTO));
        }
        String gender;
        if(userDTO.getGender()==1){
            gender = "男";
        }else {
            gender = "女";
        }
        Boolean isFollowed;
        if(uid==null){
            isFollowed=false;
        }else if(userDao.checkFollow(id, uid)>0){
            isFollowed=true;
        }else {
            isFollowed=false;
        }
        UserVO userVO = new UserVO(
                userDTO.getId(),
                userDTO.getUsername(),
                userDTO.getName(),
                gender,
                userDTO.getJob(),
                userDTO.getAddress(),
                userDTO.getFollowCount(),
                userDTO.getBeFollowedCount(),
                userDTO.getStatus(),
                isFollowed);
        return userVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void followUser(Integer follower, Integer beFollowed) {
        userDao.followUser(follower,beFollowed);
        userDao.addFollowCount(follower);
        userDao.addBeFollowedCount(beFollowed);
        String key1 = "user:"+userDao.getUsername(follower);
        String key2 = "user:"+userDao.getUsername(beFollowed);
        if(stringRedisTemplate.opsForValue().get(key1)!=null){
            stringRedisTemplate.delete(key1);
        }
        if(stringRedisTemplate.opsForValue().get(key2)!=null){
            stringRedisTemplate.delete(key2);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelFollow(Integer follower, Integer beFollowed) {
        userDao.cancelFollow(follower,beFollowed);
        userDao.reduceFollowCount(follower);
        userDao.reduceBeFollowedCount(beFollowed);
        String key1 = "user:"+userDao.getUsername(follower);
        String key2 = "user:"+userDao.getUsername(beFollowed);
        if(stringRedisTemplate.opsForValue().get(key1)!=null){
            stringRedisTemplate.delete(key1);
        }
        if(stringRedisTemplate.opsForValue().get(key2)!=null){
            stringRedisTemplate.delete(key2);
        }
    }
}
